from typing import Dict, List, Optional, Callable
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import time
import logging
import json
import requests
from dataclasses import dataclass
from threading import Thread, Lock
from queue import Queue
import os

@dataclass
class Alert:
    """警报信息"""
    level: str  # 'info', 'warning', 'error', 'critical'
    message: str
    timestamp: datetime
    data: Dict = None

class Monitor:
    """监控系统"""
    
    def __init__(
        self,
        log_dir: str = 'logs',
        alert_webhook: Optional[str] = None,
        alert_callback: Optional[Callable] = None
    ):
        """
        初始化监控系统
        
        Args:
            log_dir: 日志目录
            alert_webhook: 警报webhook URL
            alert_callback: 警报回调函数
        """
        self.log_dir = log_dir
        self.alert_webhook = alert_webhook
        self.alert_callback = alert_callback
        self.alert_queue = Queue()
        self.metrics = {}
        self.metrics_lock = Lock()
        self.running = False
        
        # 创建日志目录
        os.makedirs(log_dir, exist_ok=True)
        
        # 配置日志
        self.setup_logging()
        
        # 启动警报处理线程
        self.alert_thread = Thread(target=self._process_alerts)
        self.alert_thread.daemon = True
        
    def setup_logging(self):
        """配置日志系统"""
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler(
                    os.path.join(self.log_dir, f'monitor_{datetime.now().strftime("%Y%m%d")}.log')
                ),
                logging.StreamHandler()
            ]
        )
        self.logger = logging.getLogger('Monitor')
        
    def start(self):
        """启动监控系统"""
        self.running = True
        self.alert_thread.start()
        self.logger.info("监控系统已启动")
        
    def stop(self):
        """停止监控系统"""
        self.running = False
        self.alert_thread.join()
        self.logger.info("监控系统已停止")
        
    def update_metric(self, name: str, value: float, timestamp: datetime = None):
        """
        更新指标
        
        Args:
            name: 指标名称
            value: 指标值
            timestamp: 时间戳
        """
        timestamp = timestamp or datetime.now()
        with self.metrics_lock:
            if name not in self.metrics:
                self.metrics[name] = []
            self.metrics[name].append((timestamp, value))
            
            # 清理旧数据（保留24小时）
            cutoff = timestamp - timedelta(hours=24)
            self.metrics[name] = [
                (ts, val) for ts, val in self.metrics[name]
                if ts > cutoff
            ]
            
    def get_metric_stats(self, name: str) -> Dict:
        """
        获取指标统计信息
        
        Args:
            name: 指标名称
            
        Returns:
            指标统计信息
        """
        with self.metrics_lock:
            if name not in self.metrics or not self.metrics[name]:
                return {}
                
            values = [val for _, val in self.metrics[name]]
            timestamps = [ts for ts, _ in self.metrics[name]]
            
            return {
                'current': values[-1],
                'mean': np.mean(values),
                'std': np.std(values),
                'min': np.min(values),
                'max': np.max(values),
                'last_update': timestamps[-1]
            }
            
    def add_alert(self, alert: Alert):
        """
        添加警报
        
        Args:
            alert: 警报信息
        """
        self.alert_queue.put(alert)
        self.logger.warning(f"新警报: {alert.message}")
        
    def _process_alerts(self):
        """处理警报队列"""
        while self.running:
            try:
                alert = self.alert_queue.get(timeout=1)
                self._handle_alert(alert)
            except Exception as e:
                if self.running:
                    self.logger.error(f"处理警报时出错: {str(e)}")
                    
    def _handle_alert(self, alert: Alert):
        """
        处理警报
        
        Args:
            alert: 警报信息
        """
        # 记录警报
        self.logger.log(
            getattr(logging, alert.level.upper()),
            f"警报: {alert.message}"
        )
        
        # 发送webhook通知
        if self.alert_webhook:
            try:
                requests.post(
                    self.alert_webhook,
                    json={
                        'level': alert.level,
                        'message': alert.message,
                        'timestamp': alert.timestamp.isoformat(),
                        'data': alert.data
                    }
                )
            except Exception as e:
                self.logger.error(f"发送webhook通知失败: {str(e)}")
                
        # 调用回调函数
        if self.alert_callback:
            try:
                self.alert_callback(alert)
            except Exception as e:
                self.logger.error(f"调用警报回调函数失败: {str(e)}")
                
    def check_price_alert(self, symbol: str, price: float, thresholds: Dict[str, float]):
        """
        检查价格警报
        
        Args:
            symbol: 交易对
            price: 当前价格
            thresholds: 阈值配置
        """
        if price > thresholds.get('upper', float('inf')):
            self.add_alert(Alert(
                level='warning',
                message=f"{symbol}价格超过上限: {price}",
                timestamp=datetime.now(),
                data={'symbol': symbol, 'price': price, 'threshold': thresholds['upper']}
            ))
        elif price < thresholds.get('lower', float('-inf')):
            self.add_alert(Alert(
                level='warning',
                message=f"{symbol}价格低于下限: {price}",
                timestamp=datetime.now(),
                data={'symbol': symbol, 'price': price, 'threshold': thresholds['lower']}
            ))
            
    def check_volatility_alert(self, symbol: str, volatility: float, threshold: float):
        """
        检查波动率警报
        
        Args:
            symbol: 交易对
            volatility: 当前波动率
            threshold: 阈值
        """
        if volatility > threshold:
            self.add_alert(Alert(
                level='warning',
                message=f"{symbol}波动率异常: {volatility:.2%}",
                timestamp=datetime.now(),
                data={'symbol': symbol, 'volatility': volatility, 'threshold': threshold}
            ))
            
    def check_drawdown_alert(self, symbol: str, drawdown: float, threshold: float):
        """
        检查回撤警报
        
        Args:
            symbol: 交易对
            drawdown: 当前回撤
            threshold: 阈值
        """
        if abs(drawdown) > threshold:
            self.add_alert(Alert(
                level='warning',
                message=f"{symbol}回撤超过阈值: {drawdown:.2%}",
                timestamp=datetime.now(),
                data={'symbol': symbol, 'drawdown': drawdown, 'threshold': threshold}
            ))
            
    def check_position_alert(self, symbol: str, position_size: float, thresholds: Dict[str, float]):
        """
        检查持仓警报
        
        Args:
            symbol: 交易对
            position_size: 持仓大小
            thresholds: 阈值配置
        """
        if position_size > thresholds.get('max', float('inf')):
            self.add_alert(Alert(
                level='warning',
                message=f"{symbol}持仓超过上限: {position_size}",
                timestamp=datetime.now(),
                data={'symbol': symbol, 'position': position_size, 'threshold': thresholds['max']}
            ))
            
    def check_pnl_alert(self, symbol: str, daily_pnl: float, threshold: float):
        """
        检查收益警报
        
        Args:
            symbol: 交易对
            daily_pnl: 当日收益
            threshold: 阈值
        """
        if daily_pnl < -threshold:
            self.add_alert(Alert(
                level='warning',
                message=f"{symbol}当日亏损超过阈值: {daily_pnl:.2f}",
                timestamp=datetime.now(),
                data={'symbol': symbol, 'pnl': daily_pnl, 'threshold': threshold}
            ))
            
    def generate_status_report(self) -> str:
        """
        生成状态报告
        
        Returns:
            状态报告
        """
        with self.metrics_lock:
            report = "系统状态报告\n"
            report += "=" * 50 + "\n"
            report += f"生成时间: {datetime.now()}\n\n"
            
            for name, data in self.metrics.items():
                if not data:
                    continue
                    
                stats = self.get_metric_stats(name)
                report += f"{name}:\n"
                report += f"  当前值: {stats['current']}\n"
                report += f"  平均值: {stats['mean']:.2f}\n"
                report += f"  标准差: {stats['std']:.2f}\n"
                report += f"  最小值: {stats['min']}\n"
                report += f"  最大值: {stats['max']}\n"
                report += f"  最后更新: {stats['last_update']}\n"
                report += "-" * 30 + "\n"
                
            return report
